package com.heima.schedule.service;

import com.alibaba.fastjson.JSON;
import com.heima.common.cache.CacheService;
import com.heima.model.schedule.dto.Task;
import com.heima.model.schedule.pojos.Taskinfo;
import com.heima.model.schedule.pojos.TaskinfoLogs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Set;

@Service
@Slf4j
public class TaskServiceImpl implements TaskService {

    @Autowired
    private TaskinfoService taskinfoService;

    @Autowired
    private TaskinfoLogsService taskinfoLogsService;

    @Autowired
    private CacheService cacheService;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Long addTask(Task task) {
        if(task == null){
            log.warn("入参不能为空");
            return null;
        }
        // 添加任务到task的时间
        long executeTime = task.getExecuteTime();

        Taskinfo taskInfo = new Taskinfo();
        BeanUtils.copyProperties(task, taskInfo);
        taskInfo.setExecuteTime(new Date(executeTime));

        boolean taskResult = taskinfoService.save(taskInfo);
        if (!taskResult) {
            log.warn("任务插入失败");
            return null;
        }

        // 添加任务到log表
        TaskinfoLogs logs = new TaskinfoLogs();
        BeanUtils.copyProperties(task,logs);
        logs.setExecuteTime(new Date(task.getExecuteTime()));
        logs.setStatus(0);

        boolean logsResult = taskinfoLogsService.save(logs);
        if(!logsResult){
            log.warn("日志插入失败");
            throw new RuntimeException("日志插入失败");
        }

        //判断任务执行时间是否少于当前时间
        //当前时间
        long currentTime = System.currentTimeMillis();
        if(executeTime <= currentTime){
            //加入到当前执行队列
            cacheService.lLeftPush("TOPIC",JSON.toJSONString(task));
        }

        //判断任务执行时间是否小于未来五分钟
        long futureTime = currentTime + (5*60*1000);
        if(executeTime <= futureTime){
            cacheService.zAdd("FUTURE",JSON.toJSONString(task),executeTime);
        }

        //返回任务id
        return taskInfo.getTaskId();
    }

    @Override//取消任务
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean cancelTask(Long taskId) {
       if(taskId == null){
           log.warn("没有待取消任务");
           return false;
       }
       //删除任务
       boolean removeResult = taskinfoService.removeById(taskId);
       if(!removeResult){
           log.warn("任务取消失败");
           return false;
       }

        //查找并更新任务日志
        TaskinfoLogs logs = taskinfoLogsService.getById(taskId);
        logs.setStatus(2);
        boolean updateResult = taskinfoLogsService.updateById(logs);
        if (!updateResult){
            log.warn("任务日志更新失败");
            throw new RuntimeException("任务日志更新失败");
        }
        //组装task
        Task task = new Task();
        BeanUtils.copyProperties(logs,task);
        task.setExecuteTime(logs.getExecuteTime().getTime());
        if(task.getExecuteTime() <= System.currentTimeMillis()){
            cacheService.lRemove("TOPIC",0,JSON.toJSONString(task));
        }else {
            cacheService.zRemove("FUTURE",JSON.toJSONString(task));
        }
        return true;
    }

    @Override//消费任务
    @Transactional(rollbackFor = RuntimeException.class)
    public Boolean pollTask() {
        String rightPop = cacheService.lRightPop("TOPIC");
        if(StringUtils.isEmpty(rightPop)){
            log.warn("消费任务为空");
            return false;
        }

        Task task = JSON.parseObject(rightPop, Task.class);
        Long taskId = task.getTaskId();
        boolean removeResult = taskinfoService.removeById(taskId);
        if(!removeResult){
            log.warn("任务"+taskId+"删除失败");
            return null;
        }

        TaskinfoLogs taskinfoLogs = taskinfoLogsService.getById(taskId);
        taskinfoLogs.setStatus(1);
        boolean updateResult = taskinfoLogsService.updateById(taskinfoLogs);
        if(!updateResult){
            log.warn("日志更新失败");
            throw new RuntimeException("日志更新失败");
        }
        return true;
    }

    //定时刷新
    @Scheduled(fixedRate = 1000*5*60)
    public void refresh(){

        String token = cacheService.tryLock("FUTURE_TASK_SYNC", 5000);
        if(StringUtils.isBlank(token)){
            return;
        }
        log.info("定时刷新任务进行了");
        Set<String> tasks = cacheService.zRangeByScore("FUTURE", 0, System.currentTimeMillis());
        if(!tasks.isEmpty()){
            cacheService.refreshWithPipeline("FUTURE","TOPIC",tasks);
        }
    }

    //初始化redis
    @Scheduled(fixedRate = 1000*60*5)
    public void initDate(){
        //清除缓存
        clean();
        List<Taskinfo> list = taskinfoService.list();
        if(CollectionUtils.isEmpty(list)){
            log.warn("任务为空");
            return;
        }
        //遍历获得的数据
        for (Taskinfo taskinfo : list) {
            if(taskinfo == null){
                continue;
            }
            //获取任务时间,当前时间,未来5分钟内时间
            long executeTime = taskinfo.getExecuteTime().getTime();
            long currentTime = System.currentTimeMillis();
            long futureTime = currentTime+(1000*60*5);
            //new一个任务  按时间存入队列
            Task task = new Task();
            BeanUtils.copyProperties(taskinfo,task);
            task.setExecuteTime(executeTime);
            if (executeTime <= currentTime) {
                cacheService.lLeftPush("TOPIC", JSON.toJSONString(task));
            } else if (executeTime <= futureTime) {
                cacheService.zAdd("FUTURE", JSON.toJSONString(task), executeTime);
            }
        }

    }
    private void clean(){
        cacheService.delete("TOPIC");
        cacheService.delete("FUTURE");
    }
}
